package com.zs.games.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.regex.Pattern;

/**
 * @author
 * @description: 时间帮助类
 **/
public final class DateUtil {

    private static Logger logger = LoggerFactory.getLogger(DateUtil.class);

    public static final String FULL_TIME_PATTERN = "yyyyMMddHHmmss";
    public static final String FULL_TIME_SPLIT_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String CST_TIME_PATTERN = "EEE MMM dd HH:mm:ss zzz yyyy";

    public static final String FORMAT_YYYY_MM;
    public static final String FORMAT_YYYY_MM_DD;
    public static final String FORMAT_YMDHMS;
    public static final Pattern PATTERN_YYYY_MM;
    public static final Pattern PATTERN_YYYY_MM_DD;
    public static final Pattern PATTERN_YYYY_MM_DD_HH_MM_SS;
    public static int SECONDS_IN_DAY = 60 * 60 * 24;
    public static final long MILLIS_IN_DAY = 1000L * SECONDS_IN_DAY;
    private static final long ONE_MINUTE = 60;
    private static final long ONE_HOUR = 60 * ONE_MINUTE;
    private static final long ONE_DAY = 24 * ONE_HOUR;
    private static final long ONE_MONTH = 30 * ONE_DAY;
    private static final long ONE_YEAR = 365 * ONE_DAY;

    static {
        FORMAT_YMDHMS = "yyyy-MM-dd HH:mm:ss";
        FORMAT_YYYY_MM_DD = "yyyy-MM-dd";
        FORMAT_YYYY_MM = "yyyy-MM";
        PATTERN_YYYY_MM_DD_HH_MM_SS = Pattern.compile("[0-9]{4}-[0-9]{1,2}-[0-9]{1,2} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}");
        PATTERN_YYYY_MM_DD = Pattern.compile("[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}");
        PATTERN_YYYY_MM = Pattern.compile("[0-9]{4}-[0-9]{1,2}");
    }



    public static String getFullString() {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }

    public static String getYMDString() {
        return new SimpleDateFormat("yyyyMMdd").format(new Date());
    }

    public static String getYMString() {
        return new SimpleDateFormat("yyyyMM").format(new Date());
    }



    public static String getFromateDate(Date date,String format) {
        return new SimpleDateFormat(format).format(date);
    }
    public static String getTimeString(long millis) {
        SimpleDateFormat format = new SimpleDateFormat(FORMAT_YMDHMS);
        return format.format(millis);
//        return FORMAT_YMDHMS.format(new Date(millis));
    }

    public static Date toDate(String strDate) {
        strDate = strDate.replaceAll("/", "-");
        try {
            if (PATTERN_YYYY_MM_DD_HH_MM_SS.matcher(strDate).find()) {
                SimpleDateFormat format = new SimpleDateFormat(FORMAT_YMDHMS);
                return format.parse(strDate);
                /* return FORMAT_YMDHMS.parse(strDate);*/
            } else if (PATTERN_YYYY_MM_DD.matcher(strDate).find()) {
                SimpleDateFormat format = new SimpleDateFormat(FORMAT_YYYY_MM_DD);
                return format.parse(strDate);
                /*return FORMAT_YYYY_MM_DD.parse(strDate);*/
            } else if (PATTERN_YYYY_MM.matcher(strDate).find()) {
                SimpleDateFormat format = new SimpleDateFormat(FORMAT_YYYY_MM);
                return format.parse(strDate);
                /*return FORMAT_YYYY_MM.parse(strDate);*/
            } else {
                throw new RuntimeException("未知的日期格式化字符串");
            }
        }catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    public static long toTimestamp(String strDate) {
        return toDate(strDate).getTime();
    }

    public static long toSeconds(String strDate) {
        return toTimestamp(strDate) / 1000;
    }

    /**
     * 比较两个时间的年月日是否相同
     * @param d1  时间1
     * @param d2  时间2
     * @return
     */
    public static boolean compareDayTime(Calendar d1, Calendar d2) {
        int d1_year = d1.get(Calendar.YEAR);
        int d1_month = d1.get(Calendar.MONTH);
        int d1_day = d1.get(Calendar.DAY_OF_MONTH);
        int d2_year = d2.get(Calendar.YEAR);
        int d2_month = d2.get(Calendar.MONTH);
        int d2_day = d2.get(Calendar.DAY_OF_MONTH);
        if (d1_year == d2_year && d1_month == d2_month && d1_day == d2_day) return true;
        return false;
    }

    /**
     * 比较两个时间的年月日是否相同
     * @param d1  时间1
     * @param d2  时间2
     * @return
     */
    public static boolean compareDayTime(Date d1, Date d2) {
        Calendar cal1 =Calendar.getInstance();
        Calendar cal2 =Calendar.getInstance();
        cal1.setTime(d1);
        cal2.setTime(d2);
        return compareDayTime(cal1, cal2);
    }

    /**
     * 比较两个时间的年月是否相同
     * @param d1  时间1
     * @param d2  时间2
     * @return
     */
    public static boolean compareMonthTime(Calendar d1, Calendar d2) {
        int d1_year = d1.get(Calendar.YEAR);
        int d1_month = d1.get(Calendar.MONTH);
        int d2_year = d2.get(Calendar.YEAR);
        int d2_month = d2.get(Calendar.MONTH);
        if (d1_year == d2_year && d1_month == d2_month) return true;
        return false;
    }

    /**
     * 获取上传路径的前缀
     * @return
     */
    public static Date getNextDay(Date currentDay) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(currentDay);
        calendar.add(Calendar.DATE, 1);
        Date nextDay = calendar.getTime();
        return nextDay;
    }

    /**
     *  获得当天0点时间
     * @return
     */
    public static Date getTodayMorning() {
        Calendar cal = Calendar.getInstance();
        //把当前时间赋给cal
        cal.setTime(new Date());
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     *  获得当天24点时间
     * @return
     */
    public static Date getTodayNight() {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 24);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /** @Description:（获得第n后的当前时间）
     * @param times 当前时间
     * @param days  第n天
     * @param type  0:后n天 , 1:前n天
     * @return
     **/
    public static long getOneDayNextDay(long times, int days, int type) {
        // 基数
        final long ruleTimes = 86400000;
        return (0 == type ? times + (ruleTimes * days) : times - (ruleTimes * days));
    }

    /**
     *  获得昨天0点时间
     * @return
     */
    public static Date getYesterdayMorning() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     *  获得昨天23.59点时间
     * @return
     */
    public static Date getYesterdayLastTime() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.MILLISECOND, 00);
        return cal.getTime();
    }

    /**
     *  获得昨天24点时间
     * @return
     */
    public static Date getYesterdayNight() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        cal.set(Calendar.HOUR_OF_DAY, 24);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     *  获得明天0点时间
     * @return
     */
    public static Date getTomorrowMorning() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     *  获得明天23.59点时间
     * @return
     */
    public static Date getTomorrowLastTime() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, 1);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.MILLISECOND, 00);
        return cal.getTime();
    }

    /**
     *  获得明天24点时间
     * @return
     */
    public static Date getTomorrowNight() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, 1);
        cal.set(Calendar.HOUR_OF_DAY, 24);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     *  获得今天前天明天23:59:59点时间
     * @param n 0 今天 小于0 几天前
     * @return
     */
    public static Date getNowDayNextDay(int n) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, n);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     *  获得本周一0点时间
     * @return
     */
    public static Date getWeekMorning() {
        Calendar cal = Calendar.getInstance();
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        return cal.getTime();
    }

    public static String secondsToTime(long seconds) {
        // 小时
        long h = seconds / 3600L;
        // 分钟
        long m = (seconds % 3600L) / 60;
        // 秒
        long s = (seconds % 3600L) % 60;

        if(h > 0){
            return h + "小时" +m +" 分钟" + s + "秒";
        }
        if(m > 0 && s <= 0){
            return m + "分钟";
        }

        if(m > 0){
            return m + "分钟" + s + "秒";
        }

        return s +"秒";
    }

    /**
     * 获得本周日24点时间
     * @return
     */
    public static Date getWeekNight() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getWeekMorning());
        cal.add(Calendar.DAY_OF_WEEK, 7);
        return cal.getTime();
    }

    /**
     * 获得本月第一天0点时间
     * @return
     */
    public static Date getMonthMorning() {
        Calendar cal = Calendar.getInstance();
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
        return cal.getTime();
    }

    /**
     *  获得本月最后一天24点时间
     * @return
     */
    public static Date getMonthNight() {
        Calendar cal = Calendar.getInstance();
        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.HOUR_OF_DAY, 24);
        return cal.getTime();
    }

    /**
     *  获得上月第一天0点时间
     * @return
     */
    public static Date getLastMonthMorning() {
        Calendar cal = Calendar.getInstance();
        //把当前时间赋给cal
        cal.setTime(new Date());
        cal.add(Calendar.MONTH, -1);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 00);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获取上周一0点
     * @return
     */
    public static Date getPreviousWeekday() {
        Calendar cal = Calendar.getInstance();
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        cal.add(Calendar.DATE, -7);
        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获取当前时间的前一年的0点
     */
    public static Date getLastYear() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.add(Calendar.YEAR, -1);
        cal.set(Calendar.HOUR_OF_DAY, 00);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获取当前时间的下一年的0点
     */
    public static Date getNextYear() {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.add(Calendar.YEAR, +1);
        return cal.getTime();
    }

    /**
     * 获取某个时间几天后的凌晨
     * @param date
     * @param days
     * @return
     */
    public static Date getNestDayZeroTime(Date date, int days) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH) + days, 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date newDate = calendar.getTime();
        return newDate;
    }

    /**
     * 获得当前时间n个月前的凌晨
     * @param n 几个月前
     * @return
     */
    public static Date getLastMonthZeroTime(int n) {
        Calendar cal = Calendar.getInstance();
        //把当前时间赋给cal
        cal.setTime(new Date());
        cal.add(Calendar.MONTH, -n);
        cal.set(Calendar.HOUR_OF_DAY, 00);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 获得当前时间的n个月前的时间
     * @param n 几个月前
     * @return
     */
    public static Date getLastMonth(int n) {
        Calendar cal = Calendar.getInstance();
        //把当前时间赋给cal
        cal.setTime(new Date());
        //设置为前n月
        cal.add(Calendar.MONTH, -n);
        return cal.getTime();
    }


    /**
     * 获取上周日23点59分
     * @return
     */
    public static Date getPreviousWeekSunday() {
        Calendar cal = Calendar.getInstance();
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        cal.add(Calendar.DATE, -7);
        cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.MILLISECOND, 00);
        return cal.getTime();
    }

    /**
     * 时间戳转年月日
     * @author dingyongli
     * @param strDateTime：日期时间的字符串形式
     * @return timestamp
     * @throws
     */
    public static String strToDateTime(long strDateTime) {
        String timestamp;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(strDateTime * 1000);
        timestamp = simpleDateFormat.format(date);
        return ("1970-01-01 08:00:00".equals(timestamp) ? null : timestamp);
    }

    public static String dateToStr(Date date) {//可以用
        if (date == null){
            return null;
        }
        SimpleDateFormat format = new SimpleDateFormat(FULL_TIME_SPLIT_PATTERN);
        return format.format(date);
    }

    public static Date strYYMMDDToDate(String str) {
        SimpleDateFormat format = new SimpleDateFormat(FORMAT_YYYY_MM_DD);
        try {
            return format.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将字符串装换为Date类型
     * @param time 字符串时间
     * @param pattern 匹配格式
     * @return 返回Date格式时间
     * @throws ParseException 转换异常
     */
    public static Date getDate(String time, String pattern) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        if (!StringUtils.isEmpty(time)) {
            return sdf.parse(time);
        }
        return null;
    }

    /**
     * 将Date类型装换为字符串
     * @param date 时间
     * @param pattern 匹配格式
     * @return 返回字符串格式时间
     */
    public static String getDateStr(Date date, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }

    /**
     * @Title:getFisrtDayOfMonth
     * @Description:获取某年某月的第一天
     * @param:@param year
     * @param:@param month
     * @return:String
     * @throws
     */
    public static Date getFirstDayOfMonth(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        //设置年份
        calendar.set(Calendar.YEAR, year);
        //设置月份
        calendar.set(Calendar.MONTH, month);
        //获取某月最小天数
        int firstDay = calendar.getActualMinimum(Calendar.DAY_OF_MONTH);
        //设置日历中月份的最小天数
        calendar.set(Calendar.DAY_OF_MONTH, firstDay);
        return calendar.getTime();
    }

    /**
     * @Title:getFisrtDayOfMonth
     * @Description:获取某年某月的最后一天
     * @param:@param year
     * @param:@param month
     * @return:String
     * @throws
     */
    public static Date getLastDayOfMonth(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        //设置年份
        calendar.set(Calendar.YEAR, year);
        //设置月份
        calendar.set(Calendar.MONTH, month);
        //获取某月最大天数
        int lastDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        //设置日历中月份的最大天数
        calendar.set(Calendar.DAY_OF_MONTH, lastDay);
        return calendar.getTime();
    }
    // public static String getDiff(long start, long end) {
    // long diff = end - start;
    // long day = diff / 86400;
    // long hour = diff % 86400 / 3600;
    // long minute = (diff % 86400 % 3600) / 60;
    // return MessageFormat.format("{0}天{1}时{2}分", diff / 86400, diff % 86400 /
    // 3600, (diff % 86400 % 3600) / 60);
    // }
    //

    /**
     * 检查两天是否为同一天（2个Long类型的日期格式）
     * @param ms1
     * @param ms2
     * @return
     */
    public static boolean isSameDayOfMillis(long ms1, long ms2) {
        final long interval = ms1 - ms2;
        return interval < MILLIS_IN_DAY
                && interval > -1L * MILLIS_IN_DAY
                && toDay(ms1) == toDay(ms2);
    }

    private static long toDay(long millis) {
        return (millis + TimeZone.getDefault().getOffset(millis)) / MILLIS_IN_DAY;
    }

    /**
     * 格式化时间，格式为 yyyyMMddHHmmss
     *
     * @param localDateTime LocalDateTime
     * @return 格式化后的字符串
     */
    public static String formatFullTime(LocalDateTime localDateTime) {
        return formatFullTime(localDateTime, FULL_TIME_PATTERN);
    }

    /**
     * 根据传入的格式，格式化时间
     *
     * @param localDateTime LocalDateTime
     * @param format        格式
     * @return 格式化后的字符串
     */
    public static String formatFullTime(LocalDateTime localDateTime, String format) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format);
        return localDateTime.format(dateTimeFormatter);
    }

    /**
     * 根据传入的格式，格式化时间
     *
     * @param date   Date
     * @param format 格式
     * @return 格式化后的字符串
     */
    public static String getDateFormat(Date date, String format) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format, Locale.CHINA);
        return simpleDateFormat.format(date);
    }

    /**
     * 格式化 CST类型的时间字符串
     *
     * @param date   CST类型的时间字符串
     * @param format 格式
     * @return 格式化后的字符串
     * @throws ParseException 异常
     */
    public static String formatCstTime(String date, String format) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(CST_TIME_PATTERN, Locale.US);
        Date usDate = simpleDateFormat.parse(date);
        return getDateFormat(usDate, format);
    }

    /**
     * 格式化 Instant
     *
     * @param instant Instant
     * @param format  格式
     * @return 格式化后的字符串
     */
    public static String formatInstant(Instant instant, String format) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return localDateTime.format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * 判断当前时间是否在指定时间范围
     *
     * @param from 开始时间
     * @param to   结束时间
     * @return 结果
     */
    public static boolean between(LocalTime from, LocalTime to) {
        LocalTime now = LocalTime.now();
        return now.isAfter(from) && now.isBefore(to);
    }

//    public static void main(String[] args) {
//        System.out.println(getNowDayNextDay(10));
//    }


}
